﻿// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Windows;
using DynamicData;
using ReactiveUI.Tests.Wpf;

namespace ReactiveUI.Tests;

/// <summary>
/// Tests for RoutedViewHost.
/// </summary>
/// <remarks>
/// This test fixture is marked as NonParallelizable because tests call
/// Locator.CurrentMutable.InitializeSplat() and Locator.CurrentMutable.InitializeReactiveUI(),
/// which mutate global service locator state. This state must not be mutated concurrently
/// by parallel tests.
/// </remarks>
[TestFixture]
[Apartment(ApartmentState.STA)]
[NonParallelizable]
public class RoutedViewHostTests
{
    [Test]
    public void RoutedViewHostDefaultContentNotNull()
    {
        Locator.CurrentMutable.InitializeSplat();
        Locator.CurrentMutable.InitializeReactiveUI();
        var uc = new RoutedViewHost
        {
            DefaultContent = new System.Windows.Controls.Label()
        };
        var window = new WpfTestWindow();
        window.RootGrid.Children.Add(uc);

        var activation = new ActivationForViewFetcher();

        activation.GetActivationForView(window).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var windowActivated).Subscribe();

        activation.GetActivationForView(uc).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var controlActivated).Subscribe();

        var loaded = new RoutedEventArgs
        {
            RoutedEvent = FrameworkElement.LoadedEvent
        };

        window.RaiseEvent(loaded);
        uc.RaiseEvent(loaded);

        new[] { true }.AssertAreEqual(windowActivated);
        new[] { true }.AssertAreEqual(controlActivated);

        Assert.That(uc.Content, Is.Not.Null);

        window.Dispatcher.InvokeShutdown();
    }

    [Test]
    public void RoutedViewHostDefaultContentNotNullWithViewModelAndActivated()
    {
        Locator.CurrentMutable.InitializeSplat();
        Locator.CurrentMutable.InitializeReactiveUI();
        Locator.CurrentMutable.Register<RoutingState>(static () => new());
        Locator.CurrentMutable.Register<TestViewModel>(static () => new());
        Locator.CurrentMutable.Register<IViewFor<TestViewModel>>(static () => new TestView());

        var uc = new RoutedViewHost
        {
            DefaultContent = new System.Windows.Controls.Label(),
            Router = Locator.Current.GetService<RoutingState>()!
        };
        var window = new WpfTestWindow();
        window.RootGrid.Children.Add(uc);

        var activation = new ActivationForViewFetcher();

        activation.GetActivationForView(window).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var windowActivated).Subscribe();

        activation.GetActivationForView(uc).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var controlActivated).Subscribe();

        var loaded = new RoutedEventArgs
        {
            RoutedEvent = FrameworkElement.LoadedEvent
        };

        window.RaiseEvent(loaded);
        uc.RaiseEvent(loaded);

        new[] { true }.AssertAreEqual(windowActivated);
        new[] { true }.AssertAreEqual(controlActivated);

        // Default Content
        Assert.That(uc.Content, Is.InstanceOf<System.Windows.Controls.Label>());

        // Test Navigation after activated
        uc.Router.Navigate.Execute(Locator.Current.GetService<TestViewModel>()!);
        Assert.That(uc.Content, Is.InstanceOf<TestView>());

        window.Dispatcher.InvokeShutdown();
    }

    [Test]
    public void RoutedViewHostDefaultContentNotNullWithViewModelAndNotActivated()
    {
        Locator.CurrentMutable.InitializeSplat();
        Locator.CurrentMutable.InitializeReactiveUI();
        Locator.CurrentMutable.Register<RoutingState>(static () => new());
        Locator.CurrentMutable.Register<TestViewModel>(static () => new());
        Locator.CurrentMutable.Register<IViewFor<TestViewModel>>(static () => new TestView());

        var uc = new RoutedViewHost
        {
            DefaultContent = new System.Windows.Controls.Label(),
            Router = Locator.Current.GetService<RoutingState>()!
        };
        var window = new WpfTestWindow();
        window.RootGrid.Children.Add(uc);

        var activation = new ActivationForViewFetcher();

        activation.GetActivationForView(window).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var windowActivated).Subscribe();

        activation.GetActivationForView(uc).ToObservableChangeSet(scheduler: ImmediateScheduler.Instance).Bind(out var controlActivated).Subscribe();

        var loaded = new RoutedEventArgs
        {
            RoutedEvent = FrameworkElement.LoadedEvent
        };

        // Test navigation before Activation.
        uc.Router.Navigate.Execute(Locator.Current.GetService<TestViewModel>()!);

        // Activate
        window.RaiseEvent(loaded);
        uc.RaiseEvent(loaded);

        new[] { true }.AssertAreEqual(windowActivated);
        new[] { true }.AssertAreEqual(controlActivated);

        // Test Navigation before activated
        Assert.That(uc.Content, Is.InstanceOf<TestView>());

        window.Dispatcher.InvokeShutdown();
    }
}
